package org.locker.netty;

import cn.hutool.json.JSONUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import jakarta.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.locker.netty.dto.MessageEnum;
import org.locker.netty.dto.MessageObject;
import org.springframework.stereotype.Component;

/**
 * @description
 * @author: 徐子木
 * @create: 2020-06-02 14:57
 **/
@Slf4j
@AllArgsConstructor
@Component
public class SocketServerHandler extends SimpleChannelInboundHandler<String> {


    /**
     * 这里可以引入自己业务类来处理进行的客户端连接
     */
    private MessageService messageService;

    public static SocketServerHandler socketServerHandler;

    /**
     * 解决启动加载不到自己业务类
     */
    @PostConstruct
    public void init() {
        socketServerHandler = this;
    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        handlerMsg(ctx, msg);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        socketServerHandler.messageService.removeConnection(ctx.channel());

        log.info(" channelInactive【" + ctx.channel().remoteAddress() + "】 端口连接");

    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        log.info(" channelActive【" + ctx.channel().remoteAddress() + "】 开始连接");


    }

    /**
     * 消息处理
     *
     * @param ctx
     */
    private void handlerMsg(ChannelHandlerContext ctx, String msg) {
        Channel channel = ctx.channel();
        NettyContext.setTenant(channel);
        MessageObject message = MessageObject.toMessage(msg);
        log.info("==>msg: {},verify:{}", msg, message.verify());
        if (message != null) {
            try {
                messageService.dealMessage(message);
            }catch (Exception e){
                e.printStackTrace();
            }

        }
    }


    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }


    /**
     * 这里是保持服务器与客户端长连接  进行心跳检测 避免连接断开
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent stateEvent = (IdleStateEvent) evt;
            if (messageService.hasDevice(ctx.channel())) {
                String deviceNo = messageService.getBindDeviceNo(ctx.channel());
                MessageObject messageObject = MessageObject.builder().code(MessageEnum.HEART).build();
                switch (stateEvent.state()) {
                    //读空闲（服务器端）
                    case READER_IDLE:
                        log.info("【" + ctx.channel().remoteAddress() + "】读空闲（服务器端）");
                        messageService.removeConnection(ctx.channel());
                        break;
                    //写空闲（客户端）
                    case WRITER_IDLE:
                        log.info("【" + ctx.channel().remoteAddress() + "】写空闲（客户端）");
                        messageService.sendMessage(deviceNo, messageObject);
                        break;
                    case ALL_IDLE:
                        log.info("【" + ctx.channel().remoteAddress() + "】读写空闲");
                        messageService.removeConnection(ctx.channel());
                        break;
                    default:
                        break;
                }

            } else {
                log.error(" 心跳监听【" + ctx.channel().remoteAddress() + "】 已关闭（服务器端）远程连接 【NOT LOGIN】");
                messageService.removeConnection(ctx.channel());
            }
        }
    }


    /**
     * 出现异常时
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        //移除channel
        socketServerHandler.messageService.removeConnection(ctx.channel());
        ctx.close();
        log.error(" 出现异常【" + ctx.channel().remoteAddress() + "】 已关闭（服务器端）");
    }

    public static void main(String[] args) {
        MessageObject messageObject = MessageObject.builder().code(MessageEnum.HEART).build();
        System.out.println(JSONUtil.toJsonStr(messageObject));
    }


}

